package ru.spbsu.electromenu.servlet;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.spbsu.electromenu.model.Dish;
import ru.spbsu.electromenu.model.Order;
import ru.spbsu.electromenu.model.OrderedDish;
import ru.spbsu.electromenu.service.DishService;
import ru.spbsu.electromenu.service.OrderService;
import ru.spbsu.electromenu.util.collections.CollectionUtils;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * Date: 5/1/11
 * Time: 10:50 PM
 *
 * @author Artem Titov
 */
public class ShowOrderServlet extends SpringHttpServlet {
    private static Logger logger = LoggerFactory.getLogger(ShowOrderServlet.class);
    private OrderService orderService;
    private DishService dishService;

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        orderService = getBean("orderService");
        dishService = getBean("dishService");
        if (orderService == null || dishService == null) {
            logger.error("Failed to instantiate necessary services");
            isValid = false;
            throw new IllegalStateException("Failed to instantiate necessary services");
        }
    }

    private enum Mode {
        ALL(0),
        CONFIRMED(1),
        UNCONFIRMED(2),
        ONE(3),
        DEFAULT(ALL);

        private final int code;

        private Mode(final int code) {
            this.code = code;
        }

        private Mode(final Mode mode) {
            this.code = mode.getCode();
        }

        public int getCode() {
            return code;
        }

        public static Mode forCode(final int code) {
            for (final Mode mode : values()) {
                if (code == mode.getCode()) {
                    return mode;
                }
            }
            throw new IllegalArgumentException("Mode for code " + code + " doesn't exist");
        }
    }

    private Order injectDishes(final Order order, final Map<Integer, Dish> dishes) {
        order.injectDishes(dishes);
        return order;
    }

    private List<Order> injectDishes(final List<Order> orders, final Map<Integer, Dish> dishes) {
        for (final Order order : orders) {
            order.injectDishes(dishes);
        }
        return orders;
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        if (!isValid) {
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Can't initialize environment");
            return;
        }
        final String sMode = request.getParameter("mode");
        int modeCode = Mode.DEFAULT.getCode();
        try {
            modeCode = Integer.parseInt(sMode);
        } catch (Exception e) {
            // do nothing
        }
        final Mode mode = Mode.forCode(modeCode);
        final Map<Integer, Dish> dishes = CollectionUtils.mapFromCollection(dishService.getAll());
        switch (mode) {
            case ALL: {
                request.setAttribute("orders", injectDishes(orderService.getAll(), dishes));
                dispatch(request, response, "showOrder.jsp");
            }
            break;
            case CONFIRMED: {
                request.setAttribute("orders", injectDishes(orderService.getConfirmed(true), dishes));
                dispatch(request, response, "showOrder.jsp");
            }
            break;
            case UNCONFIRMED: {
                request.setAttribute("orders", injectDishes(orderService.getConfirmed(false), dishes));
                dispatch(request, response, "showOrder.jsp");
            }
            break;
            case ONE: {
                final int orderId = getParameter(request, "order_id", -1);
                if (orderId > 0) {
                    Order order = orderService.get(orderId);
                    injectDishes(order, dishes);
                    request.setAttribute("order", order);
                    double totalPrice = 0;
                    if (order != null) {
                        for (final OrderedDish orderedDish : order.getOrderedDishes()) {
                            totalPrice += orderedDish.getDish().getPrice() * orderedDish.getAmount();
                        }
                    }
                    request.setAttribute("totalPrice", totalPrice);
                    dispatch(request, response, "bill.jsp");
                }
            }
            break;
        }
    }

    private void dispatch(final HttpServletRequest request, final HttpServletResponse response, final String name) throws IOException, ServletException {
        final RequestDispatcher dispatcher = request.getRequestDispatcher(name);
        if (dispatcher != null) {
            dispatcher.forward(request, response);
        } else {
            logger.error("Failed to get RequestDispatcher for {}", name);
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
        }
    }
}
